package com.lottery.game.websocket;

import com.google.common.collect.Lists;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.lottery.game.common.utils.DateUtils;
import com.lottery.game.common.utils.UUIDUtils;
import com.lottery.game.core.modules.entity.user.ChatRecord;
import com.lottery.game.core.modules.service.app.ChatRecordService;
import com.lottery.game.core.modules.service.app.OperationalSetService;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.util.StringUtils;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

//@Component
public class RobotSpeak {
    private static final Logger logger = LoggerFactory.getLogger(RobotSpeak.class);

    @Autowired
    private OperationalSetService operationalSetService;

    @Autowired
    private ChatRecordService chatRecordService;
    /**
     * 下注方案分割 正则
     */
    private static final Pattern pattern = Pattern.compile("[\\u4e00-\\u9fa5]+|\\d+");

    private static final String RANDOM_AMOUNT_STRING = "随机金额";

    /**
     * 机器人下注 默认随机时间ROLL值最小值
     */
    private static final int ROBOT_BET_MIN_TIME = 20;
    /**
     * 机器人下注 默认随机时间ROLL值最大值
     */
    private static final int ROBOT_BET_MAX_TIME = 60;
    /**
     * 机器人下注 默认几率
     */
    private static final int ROBOT_BET_CHANCE = 50;
    /**
     * 机器人随机下注时，每个规则下注的概率
     */
    private static final int ROBOT_RANDOM_BET_CHANCE = 35;


    /**
     * 执行发言
     */
    @Async
    public void execute(String roomNumber, long startTime, long endTime, String gameQi) {
        List<Map<String, Object>> robotData = operationalSetService.queryRobotInfo(roomNumber);
        Map<String, Object> robotConf = operationalSetService.queryDictRobot();
        int betChance = ROBOT_BET_CHANCE;
        if (robotConf.containsKey("betChance")) {
            betChance = Integer.valueOf((String) robotConf.get("betChance"));
        }
        String robotName = null;
        // 读取列表中机器人的信息
        if (robotData != null && robotData.size() > 0) {
            Random random = new Random();
            for (int i = 0; i < robotData.size(); i++) {
                try {
                    int minTime = ROBOT_BET_MIN_TIME;
                    int maxTime = ROBOT_BET_MAX_TIME;
                    // 获取机器人信息
                    Map<String, Object> map = robotData.get(i);
                    if (map.containsKey("minTime") && !StringUtils.isEmpty(map.get("minTime"))) {
                        minTime = Integer.valueOf((String) map.get("minTime"));
                    }
                    if (map.containsKey("maxTime") && !StringUtils.isEmpty(map.get("minTime"))) {
                        maxTime = Integer.valueOf((String) map.get("maxTime"));
                    }
                    String robotIcon = (String) map.get("robotIcon");
                    robotName = (String) map.get("robotName");
                    String schemeId = (String) map.get("schemeId");
                    String[] schemeIds = schemeId.split(",");
                    int r = random.nextInt(schemeIds.length - 0 + 0) + 0;
                    String robotBetScheme = operationalSetService.querySchemeId(schemeIds[r]);
                    String itemMessage = createMessage(robotBetScheme, roomNumber, false);
                    // 执行发言
                    speak(startTime, robotName, robotIcon, itemMessage, roomNumber, maxTime, minTime, endTime, gameQi, betChance, robotBetScheme);
                } catch (Exception e) {
                    logger.debug(String.format("机器人【%s】发言异常:%s", robotName, e.getMessage()));
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 根据下注方案 生成下注的推送内容
     *
     * @param robotBetScheme
     * @param roomNumber
     * @param isRandom       是否随机抽取其中几项下注
     * @return
     */
    private String createMessage(String robotBetScheme, String roomNumber, Boolean isRandom) {
        String itemMessage = "";
        if (!StringUtils.isEmpty(robotBetScheme)) {
            String[] betRules = robotBetScheme.split("\\s+");
            int amount = 0;
            //多种下注也只能使用同等下注金额，所以只取第一项下注规则的金额
            StringBuilder sb = new StringBuilder();
            for (int k = 0; k < betRules.length; k++) {
                String[] betRule = pattern(betRules[k]);
                //TODO:待调整 生成金额 转换 switch
                if (betRule[1].equals("随机金额1") && k == 0) {
                    amount = ThreadLocalRandom.current().nextInt(9) * 10 + 10;
                } else if (betRule[1].equals("随机金额2") && k == 0) {
                    amount = ThreadLocalRandom.current().nextInt(80) * 10 + 100;
                } else if (betRule[1].equals("随机金额3") && k == 0) {
                    amount = ThreadLocalRandom.current().nextInt(300) * 10 + 1000;
                } else if (betRule[1].equals("随机金额4") && k == 0) {
                    amount = ThreadLocalRandom.current().nextInt(500) * 10 + 4000;
                } else if (k == 0) {
                    amount = Integer.valueOf(betRule[1]);
                }
                if (isRandom && k == 0) {
                    double randomParameter;
                    if (amount <= 100) {
                        amount = ThreadLocalRandom.current().nextInt(5) * 10 + 10;
                    } else {
                        randomParameter = ((10.0 + ThreadLocalRandom.current().nextInt(10)) / 100);
                        amount = (int) (randomParameter * amount) / 10 * 10;
                    }
                }
                //赔率
                String plInfo = initpl(roomNumber, betRule[0]);
                if (k == 0) {
                    // 彩种类型 、赔率、下注金额
                    sb.append(String.format("%s,%s,%s|", betRule[0], plInfo, amount));
                } else {
                    if (!isRandom) {
                        sb.append(String.format("%s,%s,%s|", betRule[0], plInfo, amount));
                    } else {
                        //通过校验判断是否下注
                        if (ThreadLocalRandom.current().nextInt(100) < ROBOT_RANDOM_BET_CHANCE) {
                            sb.append(String.format("%s,%s,%s|", betRule[0], plInfo, amount));
                        }
                    }
                }
                /**
                 * TODO:待删除
                 itemMessage += betRule[0] + "," + plInfo + "," + amount;
                 if (s == 0) {
                 itemMessage += betRule[0] + "," + plinfo + "," + betRule[1];
                 } else {
                 if (s > 10 && (s % 10 != 0)) {
                 s = s / 10 * 10 + 10;
                 }
                 amount = s;
                 // 大 、赔率、下注金额
                 itemMessage += betRule[0] + "," + plinfo + "," + amount;
                 }*/
            }
            itemMessage = sb.toString();
        }
        return itemMessage.substring(0, itemMessage.length() - 1);
    }


    public void speak(long startTime, String robotName, String robotIcon, String message, String roomNuber, int maxTime,
                      int minTime, long endTime, String gameQi, int betChance, String robotBetScheme) {
        //logger.debug(String.format("机器人【%s】下注",robotName));
        Random random = new Random();

        int s = random.nextInt(maxTime - minTime + 1) + minTime;
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                long expectTime = 0;
                long endTimeTmp = endTime;

                try {
                    while (true) {
                        //TODO：判断意义不明，待检查
                        if (expectTime == 0 || expectTime <= System.currentTimeMillis()) {
                            if (expectTime != 0) {
                                sendMsgToRoom(robotName, robotIcon, message, roomNuber, gameQi);
                                logger.debug(String.format("机器人【%s】第一次下注成功", robotName));
                                //如果 二次下注概率大于1 则追加下注
                                //剩余时间小于10秒不再二次投注
                                int r = ThreadLocalRandom.current().nextInt(100);
                                logger.debug(String.format("【%s】【%s】随机数:%s",gameQi,robotName,r));
                                if (r < betChance && endTimeTmp > 10000) {
                                    //TODO:二次下注可重构下注信息message
                                    String reBetMessage = createMessage(robotBetScheme, roomNuber, true);
                                    Long l = endTimeTmp - 10000;
                                    int rebetTime = ThreadLocalRandom.current().nextInt(l.intValue());
                                    logger.debug(String.format("机器人【%s】%s秒后第二次下注", robotName, (rebetTime+1000) / 1000));
                                    Thread.sleep(rebetTime+1000);
                                    sendMsgToRoom(robotName, robotIcon, reBetMessage, roomNuber, gameQi);
                                    logger.debug(String.format("机器人【%s】第二次下注成功", robotName));
                                } else {
                                    logger.debug(String.format("机器人【%s】第二次下注判断未通过", robotName));
                                }
                                break;
                            }
                        }
                        expectTime = startTime + s * 1000;
                        endTimeTmp = endTime - s * 1000;
                        logger.debug(String.format("机器人【%s】%s秒后第一次下注", robotName, s));
                        if (endTimeTmp < 0) {
                            logger.debug("机器人结束仍未发言");
                            break;
                        }
                        Thread.sleep(1000 * s);
                        // 判断有没有封盘如果有封盘那么也结束线程
                        //TODO:封盘判断逻辑似乎错误,待删除
                        long nowTime = System.currentTimeMillis();
                        if (nowTime == endTime) {
                            logger.debug("机器人结束仍未发言");
                            break;
                        }
                    }
                } catch (Exception e) {
                    logger.debug(String.format("机器人【%s】下注线程异常:%s", robotName, e.toString()));
                    e.printStackTrace();
                }
            }
        });
        thread.start();

    }

    /**
     * 给所有的房间的人推送消息
     *
     * @param robotName
     * @param robotIcon
     * @param robotMessage
     * @param roomNuber
     */
    private void sendMsgToRoom(String robotName, String robotIcon, String robotMessage, String roomNuber, String gameQi) {
        String now = DateUtils.getNowDateString();
        Map<String, Object> msgMap = new HashMap<>();
        Map<String, String> paraMap = new HashMap<>();
        paraMap.put("robotName", robotName);
        paraMap.put("robotIcon", robotIcon);
        paraMap.put("robotMessage", robotMessage);
        paraMap.put("mySendTime", now);
        paraMap.put("nowTime", now);
        msgMap.put("robotMessage", paraMap);
        // 写入数据库 历史记录
        ChatRecord chatRecord = new ChatRecord();
        String uuid = UUID.randomUUID().toString();
        chatRecord.setId(uuid);
        chatRecord.setRoomnumber(roomNuber);
        chatRecord.setSenderphoto(robotIcon);
        chatRecord.setSendernickname(robotName);
        String[] itemMssages = robotMessage.split("\\|");
        Map<String, Object> paramMap = new HashMap<>();
        String betStr = "";
        String ballOdd = "";// 赔率
        String point = "";
        int totleAmt = 0;
        for (int j = 0; j < itemMssages.length; j++) {
            String[] str = itemMssages[j].split(",");
            String str1 = initplz(str[0]);
            if (j >= 1) {
                betStr += ",";
                ballOdd += ",";
            }
            betStr += str1; // 下的什么注
            ballOdd += str[1];
            point = str[2];
            totleAmt = Integer.parseInt(str[2]) * itemMssages.length;
        }

        paramMap.put("gameQi", gameQi);
        paramMap.put("roomId", roomNuber);
        paramMap.put("robotName", robotName);
        paramMap.put("betStr", betStr);
        paramMap.put("ballOdd", ballOdd);
        paramMap.put("point", point);
        paramMap.put("totleAmt", totleAmt);
        paramMap.put("gameId", UUIDUtils.randomUUID());
        paramMap.put("gameUserId", UUIDUtils.randomUUID());

        String orginMsg = JSON.toJSONString(paramMap);

        Map<String, String> paramMap1 = new HashMap<>();
        paramMap1.put("roomNumber", roomNuber);
        paramMap1.put("sendernickname", robotName);
        paramMap1.put("betsSend", "true");
        paramMap1.put("message", orginMsg);
        paramMap1.put("photourl", robotIcon);
        paramMap1.put("mySendTime", now);
        paramMap1.put("nowTime", now);
        // paramMap1.put("betsSend", "true");
        String msg = JSON.toJSONString(paramMap1);
        chatRecord.setMsgContent(msg);
        chatRecord.setOrginMsg(orginMsg);
        chatRecord.setSenderUserid("robot");
        chatRecord.setMessageStatus("0");
        chatRecord.setChatType("0");

        chatRecord.setTimestamp(now);

        TextMessage message = new TextMessage(JSONObject.toJSONString(msgMap));
        Map<String, WebSocketSession> sessionMap = MyHandler.webSocketMap.get(roomNuber);
        // WebSocketSession session =
        // MyHandler.webSocketMap.get(GameConstants.SYS_Param_ChatID));
        if (sessionMap != null) {
            Iterator<Entry<String, WebSocketSession>> it = sessionMap.entrySet().iterator();
            while (it.hasNext()) {
                Entry<String, WebSocketSession> tmpSession = it.next();
                MyHandler.sendMessageToUser(tmpSession.getValue(), message);// 给房间的所有的发送消息
            }
        }
        chatRecordService.addChatRecord(chatRecord);

    }


    /**
     * 初始化赔率
     *
     * @return
     */
    public String initpl(String roomNunber, String msg) {
        String plinfo = "";
        Map<String, Object> itemMap = new HashMap<>();
        itemMap.put("大", "da_pl");
        itemMap.put("单", "dan_pl");
        itemMap.put("双", "shuang_pl");
        itemMap.put("小", "xiao_pl");
        itemMap.put("大单", "dadan_pl");
        itemMap.put("大双", "dashuang_pl");
        itemMap.put("小单", "xiaodan_pl");
        itemMap.put("小双", "xiaoshuang_pl");
        itemMap.put("极大", "jida_pl");
        itemMap.put("极小", "jixiao_pl");
        itemMap.put("红波", "hongbo_pl");
        itemMap.put("蓝波", "lanbo_pl");
        itemMap.put("绿波", "lvbo_pl");
        itemMap.put("豹子", "baizi_pl");
        itemMap.put("顺子", "shunzi_pl");
        itemMap.put("对子", "duizi_pl");
        for (int i = 0; i < 28; i++) {
            itemMap.put("特码" + i, "tema" + i + "_pl");
        }
        try {

            Map<String, Object> map = operationalSetService.queryPlInfo(roomNunber);
            if (map != null) {
                if (itemMap.containsKey(msg)) {
                    if (!StringUtils.isEmpty(map.get(itemMap.get(msg)))) {
                        plinfo = (String) map.get(itemMap.get(msg));
                    }
                }
            }
            return plinfo;
        } catch (Exception e) {
            logger.debug("初始化赔率异常:", e);
            return "";
        }
    }

    /**
     * 获取英文赔率
     *
     * @return
     */
    public String initplz(String msg) {
        String plinfo = "";
        Map<String, String> itemMap = new HashMap<>();
        itemMap.put("大", "da");
        itemMap.put("单", "dan");
        itemMap.put("双", "shuang");
        itemMap.put("小", "xiao");
        itemMap.put("大单", "dadan");
        itemMap.put("大双", "dashuang");
        itemMap.put("小单", "xiaodan");
        itemMap.put("小双", "xiaoshuang");
        itemMap.put("极大", "jida");
        itemMap.put("极小", "jixiao");
        itemMap.put("红波", "hongbo");
        itemMap.put("蓝波", "lanbo");
        itemMap.put("绿波", "lvbo");
        itemMap.put("豹子", "baozi");
        itemMap.put("顺子", "shunzi");
        itemMap.put("对子", "duizi");
        for (int i = 0; i < 28; i++) {
            itemMap.put("特码" + i, "tema" + i);
        }
        try {
            if (itemMap.containsKey(msg)) {
                plinfo = itemMap.get(msg);
            }

            return plinfo;
        } catch (Exception e) {
            logger.debug("初始化赔率异常:", e);
            return "";
        }
    }


    /**
     * 分割 机器人下注方案
     *
     * @param str 下注方案 大100
     * @return
     */
    private String[] pattern(String str) {
        List<String> list = Lists.newArrayList();
        int index = str.indexOf(RANDOM_AMOUNT_STRING);
        if (index > 0) {
            list.add(str.substring(0, index - 1));
            list.add(str.substring(index, str.length() - 1));
        } else {
            Matcher m = pattern.matcher(str);
            while (m.find()) {
                list.add(m.group());
            }
        }
        return list.toArray(new String[0]);
    }

    public static void main(String[] args) {
        RobotSpeak speak = new RobotSpeak();
        String[] temp = speak.pattern("大{随机金额1}");
        for (String s : temp) {
            System.out.println(s);
        }
    }
}
